package com.suke.datamq;

import com.rabbitmq.client.Channel;
import com.suke.common.AnalysisResult;
import com.suke.constant.BIConstant;
import com.suke.domain.entity.Chart;
import com.suke.service.IChartService;
import com.suke.utils.AIDocking;
import com.suke.utils.ParseAIResponse;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;

/**
 * @author 自然醒
 * @version 1.0
 */
@Component
@Slf4j
public class MessageConsumer {

    @Autowired
    private IChartService chartService;

    @Resource
    private AIDocking aiDocking;

    /**
     * 接收消息的方法
     * @param message     接收到消息的内容，是一个字符串类型
     * @param channel     消息所在的通道，可以通过该通道与 RabbitMQ 进行交互，例如手动确认消息、拒绝消息等
     * @param deliveryTag 消息的投递标签，用于唯一标识一条消息
     */
    // 使用@SneakyThrows注解简化异常处理
    @SneakyThrows
    // 使用@RabbitListener注解指定要监听的队列名称为"suke_queue"，并设置消息的确认机制为手动确认
    @RabbitListener(queues = {BIConstant.BI_QUEUE}, ackMode = "MANUAL")
    // @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag是一个方法参数注解,用于从消息头中获取投递标签(deliveryTag),
    // 在RabbitMQ中,每条消息都会被分配一个唯一的投递标签，用于标识该消息在通道中的投递状态和顺序。
    // 通过使用@Header(AmqpHeaders.DELIVERY_TAG)注解,可以从消息头中提取出该投递标签,并将其赋值给long deliveryTag参数。
    public void receiveMessage(String message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) {
        // 使用日志记录器打印接收到的消息内容
        log.info("receiveMessage message = {}", message);
        if (message == null) {
            log.error("接收到的消息为空");
            return;
        }
        Long chartId = Long.parseLong(message);
        Chart chart = chartService.getById(chartId);
        if (chart == null) {
            log.error("图表不存在");
            return;
        }
        Chart updateChart = new Chart();
        updateChart.setId(chart.getId());
        updateChart.setStatus("running");
        boolean updateResult = chartService.updateById(updateChart);
        if (!updateResult) {
            channel.basicNack(deliveryTag, false, false);
            log.error("更新图表失败状态失败" + updateChart.getId());
            handleChartUpdateError(updateChart.getId(), "更新图表失败");
            return;
        }
        String response = aiDocking.doDataAnalysis(message, updateChart.getChartType(), updateChart.getChartData());
        AnalysisResult analysisResult = ParseAIResponse.parseResponse(response);
        if (analysisResult == null) {
            handleChartUpdateError(updateChart.getId(), "分析结果为空");
            return;
        }
        Chart resChart = new Chart();
        resChart.setId(updateChart.getId());
        resChart.setGenChart(analysisResult.getChartConfig());
        resChart.setGenResult(analysisResult.getAnalysis());
        resChart.setStatus("succeed");
        resChart.setExecMsg("分析成功");
        boolean updateResult1 = chartService.updateById(resChart);
        if (!updateResult1) {
            channel.basicNack(deliveryTag, false, false);
            handleChartUpdateError(updateChart.getId(), "更新图表失败");
        }
        // 投递标签是一个数字标识,它在消息消费者接收到消息后用于向RabbitMQ确认消息的处理状态。
        // 通过将投递标签传递给channel.basicAck(deliveryTag, false)方法,可以告知RabbitMQ该消息已经成功处理,可以进行确认和从队列中删除。
        // 手动确认消息的接收，向RabbitMQ发送确认消息
        channel.basicAck(deliveryTag, false);
    }

    private void handleChartUpdateError(long chartId, String execMessage) {
        Chart updateChartResult = new Chart();
        updateChartResult.setId(chartId);
        updateChartResult.setStatus("failed");
        updateChartResult.setExecMsg("execMessage");
        boolean updateResult = chartService.updateById(updateChartResult);
        if (!updateResult) {
            log.error("更新图表失败状态失败" + chartId + "," + execMessage);
        }
    }

}


